"""
配置管理模块
读取和验证 config.yaml 配置文件
"""
import os
import yaml
from pathlib import Path
from typing import Dict, Any, Optional, List
from pydantic import BaseModel, Field
from loguru import logger


class ProxyConfig(BaseModel):
    """代理配置"""
    http: Optional[str] = Field(None, description="HTTP代理地址，如 http://proxy.example.com:8080")
    https: Optional[str] = Field(None, description="HTTPS代理地址，如 https://proxy.example.com:8080")
    # 支持用户名密码认证
    username: Optional[str] = Field(None, description="代理用户名")
    password: Optional[str] = Field(None, description="代理密码")


class ProviderConfig(BaseModel):
    """提供商配置"""
    type: Optional[str] = Field(None, description="提供商类型（llm/image/tts）")
    apiKey: Optional[str] = Field(None, description="API密钥")
    apiSecret: Optional[str] = Field(None, description="API密钥（备用字段名）")
    model: Optional[str] = Field(None, description="模型名称")
    base_url: Optional[str] = Field(None, description="基础URL（替代原endpoint配置）")
    voice: Optional[str] = Field(None, description="音色ID")
    timeout: Optional[int] = Field(60, description="请求超时时间（秒）")
    maxRetries: Optional[int] = Field(3, description="最大重试次数")
    temperature: Optional[float] = Field(None, description="默认温度")
    maxTokens: Optional[int] = Field(None, description="默认最大token数")
    maxInputTokens: Optional[int] = Field(None, description="最大输入token数（用于校验输入是否超限）")
    maxOutputTokens: Optional[int] = Field(None, description="最大输出token数（用于判断输出是否被截断，API调用时不传入此限制）")
    proxy: Optional[ProxyConfig] = Field(None, description="HTTP代理配置（提供商级别）")
    verify: Optional[bool] = Field(True, description="SSL证书验证")
    # 支持自定义参数
    extra: Optional[Dict[str, Any]] = Field(default_factory=dict, description="额外配置参数")


class RoleConfig(BaseModel):
    """角色配置"""
    provider: str = Field(..., description="提供商名称")
    model: str = Field(..., description="模型名称")
    temperature: Optional[float] = Field(None, description="角色专用温度（可选）")


class DefaultProviderConfig(BaseModel):
    """默认提供商配置"""
    llm: str = Field(..., description="默认LLM提供商")
    image: str = Field(..., description="默认图像提供商")
    tts: str = Field(..., description="默认TTS提供商")


class ComposeConfig(BaseModel):
    """合成配置"""
    fps: int = Field(25, description="帧率")
    resolution: str = Field("1080x1920", description="分辨率")
    audio: Dict[str, Any] = Field(default_factory=lambda: {"normalize": True}, description="音频配置")


class PathsConfig(BaseModel):
    """路径配置"""
    projects: str = Field("./projects", description="项目目录")
    assets: str = Field("./assets", description="资产目录")
    outputs: str = Field("./outputs", description="输出目录")
    logs: str = Field("./logs", description="日志目录")
    prompts: str = Field("./prompts", description="提示词目录")


class LLMConfig(BaseModel):
    """LLM调用配置"""
    defaultTemperature: float = Field(0.7, description="默认温度")
    temperatures: Dict[str, float] = Field(
        default_factory=lambda: {
            "outline": 0.7,
            "novel": 0.6,
            "script": 0.5,
            "role_playing": 0.7,
            "json_extraction": 0.1
        },
        description="不同流程的专用温度参数"
    )
    defaultMaxTokens: int = Field(2000, description="默认最大token数")
    enableStreaming: bool = Field(False, description="是否启用流式输出")
    requestTimeout: int = Field(60, description="请求超时时间（秒）")
    maxRetries: int = Field(3, description="最大重试次数")


class CharacterReferencesConfig(BaseModel):
    """角色参考图配置"""
    count: int = Field(4, description="每个角色生成的参考图数量")
    types: List[str] = Field(
        default_factory=lambda: ["front_view", "side_view", "expression_smile", "expression_serious"],
        description="参考图类型列表"
    )


class GenerationConfig(BaseModel):
    """生成配置"""
    firstEpisodeMinutes: int = Field(4, description="第一集目标时长（分钟），3-5分钟范围")
    defaultEpisodeMinutes: float = Field(3.5, description="默认单集时长（分钟），3-4分钟范围")
    minEpisodeSeconds: int = Field(180, description="单集最短时长（秒），即3分钟")
    maxEpisodeSeconds: int = Field(240, description="单集最长时长（秒），即4分钟")
    characterReferences: CharacterReferencesConfig = Field(
        default_factory=CharacterReferencesConfig,
        description="角色参考图配置（必选，保证人物一致性）"
    )
    videoGenerationMode: str = Field(
        "image2video",
        description="视频生成模式：text2video|image2video，默认 image2video（推荐）"
    )


class Config(BaseModel):
    """全局配置"""
    projectRoot: str = Field(".", description="项目根目录")
    defaultProvider: DefaultProviderConfig = Field(..., description="默认提供商")
    roles: Dict[str, RoleConfig] = Field(default_factory=dict, description="角色配置")
    providers: Dict[str, ProviderConfig] = Field(..., description="提供商配置")
    llm: Optional[LLMConfig] = Field(default_factory=LLMConfig, description="LLM调用配置")
    proxy: Optional[ProxyConfig] = Field(None, description="全局HTTP代理配置")
    compose: ComposeConfig = Field(default_factory=ComposeConfig, description="合成配置")
    paths: PathsConfig = Field(default_factory=PathsConfig, description="路径配置")
    generation: GenerationConfig = Field(default_factory=GenerationConfig, description="生成配置")


_config: Optional[Config] = None


def load_config(config_path: str = "config.yaml") -> Config:
    """
    加载配置文件
    
    Args:
        config_path: 配置文件路径
        
    Returns:
        Config对象
        
    Raises:
        FileNotFoundError: 配置文件不存在
        ValueError: 配置格式错误
    """
    global _config
    
    if _config is not None:
        return _config
    
    if not os.path.exists(config_path):
        logger.warning(f"配置文件不存在: {config_path}，使用默认配置")
        _config = _create_default_config()
        return _config
    
    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            data = yaml.safe_load(f)
        
        _config = Config(**data)
        logger.info(f"已加载配置: {config_path}")
        return _config
    except Exception as e:
        logger.error(f"加载配置失败: {e}")
        raise ValueError(f"配置格式错误: {e}")


def get_config() -> Config:
    """
    获取当前配置（单例）
    
    Returns:
        Config对象
    """
    if _config is None:
        return load_config()
    return _config


def _create_default_config() -> Config:
    """
    创建默认配置（当配置文件不存在时使用）
    
    Returns:
        Config对象，包含默认的提供商、路径等配置
    """
    return Config(
        projectRoot=".",
        defaultProvider=DefaultProviderConfig(
            llm="openai",
            image="imagegen",
            tts="ttsx"
        ),
        roles={},
        providers={
            "openai": ProviderConfig(
                type="llm",
                apiKey="YOUR_OPENAI_KEY",
                model="gpt-4o-mini",
                base_url="https://api.openai.com/v1"
            ),
            "claude": ProviderConfig(
                type="llm",
                apiKey="YOUR_ANTHROPIC_KEY",
                model="claude-3-5-sonnet-20241022",
                base_url="https://api.anthropic.com/v1"
            ),
            "gemini": ProviderConfig(
                type="llm",
                apiKey="YOUR_GOOGLE_API_KEY",
                model="gemini-pro",
                base_url="https://generativelanguage.googleapis.com/v1beta/models"
            ),
            "moonshot": ProviderConfig(
                type="llm",
                apiKey="YOUR_MOONSHOT_KEY",
                model="moonshot-v1-8k",
                base_url="https://api.moonshot.cn/v1"
            ),
            "imagegen": ProviderConfig(
                type="image",
                apiKey="YOUR_IMAGE_API_KEY",
                base_url="https://api.imagegen.example"
            ),
            "ttsx": ProviderConfig(
                type="tts",
                apiKey="YOUR_TTS_KEY",
                voice="narrator_cn_01"
            )
        },
        llm=LLMConfig(),
        compose=ComposeConfig(),
        generation=GenerationConfig(),
        paths=PathsConfig()
    )


def get_provider_config(provider_name: str) -> Optional[ProviderConfig]:
    """
    获取指定提供商的配置
    
    Args:
        provider_name: 提供商名称
        
    Returns:
        ProviderConfig对象，不存在返回None
    """
    config = get_config()
    return config.providers.get(provider_name)


def get_role_config(role_name: str) -> Optional[RoleConfig]:
    """
    获取指定角色的配置
    
    Args:
        role_name: 角色名称
        
    Returns:
        RoleConfig对象，不存在返回None
    """
    config = get_config()
    return config.roles.get(role_name)

